package site.isscloud.project.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import site.isscloud.project.domain.PjAlarmEvent;
import site.isscloud.project.domain.PjAlarmRecord;
import site.isscloud.project.mapper.PjAlarmEventMapper;
import site.isscloud.project.mapper.PjAlarmRecordMapper;
import site.isscloud.project.service.IPjAlarmEventService;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 告警事件Service业务层处理
 */
@Service
public class PjAlarmEventServiceImpl implements IPjAlarmEventService {

    private static final Logger log = LoggerFactory.getLogger(PjAlarmEventServiceImpl.class);
    private static final Logger alarmLog = LoggerFactory.getLogger("alarm");
    private static final Logger eventLog = LoggerFactory.getLogger("event");

    // 事件超时时间（3分钟）
    private static final int EVENT_TIMEOUT_MINUTES = 3;

    @Autowired
    private PjAlarmEventMapper pjAlarmEventMapper;

    @Autowired
    private PjAlarmRecordMapper pjAlarmRecordMapper;

    /**
     * 查询告警事件
     */
    @Override
    public PjAlarmEvent selectPjAlarmEventById(Long id) {
        return pjAlarmEventMapper.selectPjAlarmEventById(id);
    }

    /**
     * 查询告警事件列表
     */
    @Override
    public List<PjAlarmEvent> selectPjAlarmEventList(PjAlarmEvent pjAlarmEvent) {
        if (pjAlarmEvent.getAlarmType() != null && pjAlarmEvent.getAlarmType() == 3) {
            // 温度告警查询
            return pjAlarmEventMapper.selectTemperatureAlarmEventList(pjAlarmEvent);
        } else if (pjAlarmEvent.getAlarmType() != null) {
            // 指定类型的非温度告警查询
            return pjAlarmEventMapper.selectNonTemperatureAlarmEventList(pjAlarmEvent);
        } else {
            // 查询所有类型：温度告警 + 非温度告警
            List<PjAlarmEvent> result = new ArrayList<>();
            result.addAll(pjAlarmEventMapper.selectTemperatureAlarmEventList(pjAlarmEvent));
            result.addAll(pjAlarmEventMapper.selectNonTemperatureAlarmEventList(pjAlarmEvent));
            result.sort((a, b) -> b.getAlarmStartTime().compareTo(a.getAlarmStartTime()));
            return result;
        }
    }

    /**
     * 新增告警事件
     */
    @Override
    @Transactional
    public int insertPjAlarmEvent(PjAlarmEvent pjAlarmEvent) {
        pjAlarmEvent.setCreateTime(new Date());
        pjAlarmEvent.setUpdateTime(new Date());
        if (pjAlarmEvent.getEventStatus() == null) {
            pjAlarmEvent.setEventStatus(0); // 默认活跃中
        }
        if (pjAlarmEvent.getAlarmCount() == null) {
            pjAlarmEvent.setAlarmCount(1);
        }

        int result = pjAlarmEventMapper.insertPjAlarmEvent(pjAlarmEvent);

        eventLog.info("新增告警事件 - 事件ID: {}, 事件编号: {}, 设备: {}, 通道: {}, 类型: {}",
                pjAlarmEvent.getId(), pjAlarmEvent.getEventNo(),
                pjAlarmEvent.getDeviceNo(), pjAlarmEvent.getChanel(),
                pjAlarmEvent.getAlarmType());

        return result;
    }

    /**
     * 修改告警事件
     */
    @Override
    public int updatePjAlarmEvent(PjAlarmEvent pjAlarmEvent) {
        pjAlarmEvent.setUpdateTime(new Date());
        return pjAlarmEventMapper.updatePjAlarmEvent(pjAlarmEvent);
    }

    /**
     * 批量删除告警事件
     */
    @Override
    public int deletePjAlarmEventByIds(Long[] ids) {
        return pjAlarmEventMapper.deletePjAlarmEventByIds(ids);
    }

    /**
     * 删除告警事件信息
     */
    @Override
    public int deletePjAlarmEventById(Long id) {
        return pjAlarmEventMapper.deletePjAlarmEventById(id);
    }

    /**
     * 根据事件编号查询
     */
    @Override
    public PjAlarmEvent selectPjAlarmEventByEventNo(String eventNo) {
        return pjAlarmEventMapper.selectPjAlarmEventByEventNo(eventNo);
    }

    /**
     * 处理告警记录并关联事件
     */
    @Override
    @Transactional
    public void processAlarmRecord(PjAlarmRecord alarmRecord) {
        try {
            eventLog.info("开始处理告警记录关联事件 - 记录ID: {}, 设备: {}, 通道: {}, 类型: {}, 米标: {}",
                    alarmRecord.getId(), alarmRecord.getDeviceNo(), alarmRecord.getChanel(),
                    alarmRecord.getAlarmType(), alarmRecord.getMeterMark());

            // 根据告警类型分别处理
            switch (alarmRecord.getAlarmType()) {
                case 1: // 断纤告警
                    processFiberAlarm(alarmRecord);
                    break;
                case 2: // 激光器故障
                    processLaserAlarm(alarmRecord);
                    break;
                case 3: // 温度告警
                    processTemperatureAlarm(alarmRecord);
                    break;
                default:
                    eventLog.warn("未知的告警类型: {}, 记录ID: {}", alarmRecord.getAlarmType(), alarmRecord.getId());
                    break;
            }

            eventLog.info("告警记录关联事件处理完成 - 记录ID: {}", alarmRecord.getId());

        } catch (Exception e) {
            eventLog.error("处理告警记录关联事件失败 - 记录ID: {}, 错误: {}", alarmRecord.getId(), e.getMessage(), e);
            throw new RuntimeException("处理告警记录关联事件失败", e);
        }
    }

    /**
     * 处理断纤告警
     */
    private void processFiberAlarm(PjAlarmRecord alarmRecord) {
        // 断纤告警的关键标识：设备号 + 通道 + 断纤位置
        List<PjAlarmEvent> activeEvents = pjAlarmEventMapper.selectActiveEventsByDeviceChannelTypeMeter(
                alarmRecord.getDeviceNo(),
                alarmRecord.getChanel(),
                alarmRecord.getAlarmType(),
                alarmRecord.getFiberBreakPosition() // 使用断纤位置作为标识
        );

        handleAlarmEvent(activeEvents, alarmRecord, alarmRecord.getFiberBreakPosition());
    }

    /**
     * 处理激光器故障告警
     */
    private void processLaserAlarm(PjAlarmRecord alarmRecord) {
        // 激光器故障的关键标识：设备号 + 通道 + 告警类型
        // 同一个设备同一个通道的激光器故障都归为同一个事件
        List<PjAlarmEvent> activeEvents = pjAlarmEventMapper.selectActiveEventsByDeviceChannelType(
                alarmRecord.getDeviceNo(),
                alarmRecord.getChanel(),
                alarmRecord.getAlarmType()
        );

        handleAlarmEvent(activeEvents, alarmRecord, null);
    }

    /**
     * 处理温度告警
     */
    private void processTemperatureAlarm(PjAlarmRecord alarmRecord) {
        // 温度告警的关键标识：设备号 + 通道 + 米标
        List<PjAlarmEvent> activeEvents = pjAlarmEventMapper.selectActiveEventsByDeviceChannelTypeMeter(
                alarmRecord.getDeviceNo(),
                alarmRecord.getChanel(),
                alarmRecord.getAlarmType(),
                alarmRecord.getMeterMark()
        );

        handleAlarmEvent(activeEvents, alarmRecord, alarmRecord.getMeterMark());
    }

    /**
     * 通用的告警事件处理逻辑
     */
    private void handleAlarmEvent(List<PjAlarmEvent> activeEvents, PjAlarmRecord alarmRecord, Integer eventKey) {
        PjAlarmEvent targetEvent = null;

        if (activeEvents.isEmpty()) {
            // 没有活跃事件，创建新事件
            targetEvent = createNewEvent(alarmRecord, eventKey);
            eventLog.info("创建新告警事件 - 类型: {}, 事件ID: {}, 事件编号: {}",
                    getAlarmTypeName(alarmRecord.getAlarmType()), targetEvent.getId(), targetEvent.getEventNo());
        } else {
            // 有活跃事件，选择第一个（理论上应该只有一个）
            targetEvent = activeEvents.get(0);
            eventLog.info("找到活跃事件 - 类型: {}, 事件ID: {}, 事件编号: {}",
                    getAlarmTypeName(alarmRecord.getAlarmType()), targetEvent.getId(), targetEvent.getEventNo());
        }

        // 更新事件统计信息
        updateEventWithNewAlarm(targetEvent, alarmRecord);
    }

    /**
     * 创建新事件（支持不同类型）
     */
    private PjAlarmEvent createNewEvent(PjAlarmRecord alarmRecord, Integer eventKey) {
        PjAlarmEvent newEvent = new PjAlarmEvent();

        // 生成事件编号
        String eventNo = generateEventNo(alarmRecord, eventKey);
        newEvent.setEventNo(eventNo);
        newEvent.setDeviceNo(alarmRecord.getDeviceNo());
        newEvent.setChanel(alarmRecord.getChanel());
        newEvent.setAlarmType(alarmRecord.getAlarmType());
        newEvent.setAlarmStartTime(alarmRecord.getCreateTime());

        // 设置创建时间和更新时间
        Date now = new Date();
        newEvent.setCreateTime(now);
        newEvent.setUpdateTime(now);

        // 根据告警类型设置不同的关键字段
        switch (alarmRecord.getAlarmType()) {
            case 1: // 断纤告警
                newEvent.setMeterMark(null); // 使用断纤位置作为标识
                newEvent.setFiberBreakPosition(alarmRecord.getFiberBreakPosition());
                break;
            case 2: // 激光器故障
                // 激光器故障不需要米标和具体位置标识
                newEvent.setMeterMark(null);
                newEvent.setLaserTemperature(alarmRecord.getLaserTemperature());
                break;
            case 3: // 温度告警
                newEvent.setMeterMark(eventKey); // 使用米标作为标识
                if (alarmRecord.getMeterAlarmTemperature() != null) {
                    BigDecimal temp = alarmRecord.getMeterAlarmTemperature();
                    newEvent.setMaxTemperature(temp);
                    newEvent.setMinTemperature(temp);
                    newEvent.setAvgTemperature(temp);
                }
                break;
        }

        // 设置关闭时间（第一个告警记录时间 + 3分钟）
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(alarmRecord.getCreateTime());
        calendar.add(Calendar.MINUTE, EVENT_TIMEOUT_MINUTES);
        newEvent.setAlarmCloseTime(calendar.getTime());

        newEvent.setEventStatus(0); // 活跃中
        newEvent.setAlarmCount(1);
        newEvent.setFirstAlarmId(alarmRecord.getId());
        newEvent.setLastAlarmId(alarmRecord.getId());

        // 初始化告警ID数组
        JSONArray alarmIdsArray = new JSONArray();
        alarmIdsArray.add(alarmRecord.getId());
        newEvent.setAlarmIds(alarmIdsArray.toJSONString());

        pjAlarmEventMapper.insertPjAlarmEvent(newEvent);
        return newEvent;
    }

    /**
     * 更新事件统计信息
     */
    private void updateEventWithNewAlarm(PjAlarmEvent event, PjAlarmRecord newAlarm) {
        try {
            // 1. 更新基础信息
            event.setLastAlarmId(newAlarm.getId());
            event.setAlarmCount(event.getAlarmCount() + 1);
            event.setUpdateTime(new Date()); // 更新更新时间

            // 更新关闭时间（最后一个告警记录时间 + 3分钟）
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(newAlarm.getCreateTime()); // 使用新告警记录的时间
            calendar.add(Calendar.MINUTE, EVENT_TIMEOUT_MINUTES);
            event.setAlarmCloseTime(calendar.getTime());

            // 2. 更新告警ID数组 - 修复重复问题
            JSONArray alarmIdsArray;
            try {
                alarmIdsArray = JSON.parseArray(event.getAlarmIds());
                if (alarmIdsArray == null) {
                    alarmIdsArray = new JSONArray();
                }
            } catch (Exception e) {
                eventLog.warn("解析告警ID数组失败，创建新数组 - 事件ID: {}, 原数据: {}", event.getId(), event.getAlarmIds());
                alarmIdsArray = new JSONArray();
            }

            // 检查新告警ID是否已存在，避免重复
            Long newAlarmId = newAlarm.getId();
            boolean exists = false;
            for (int i = 0; i < alarmIdsArray.size(); i++) {
                if (newAlarmId.equals(alarmIdsArray.getLong(i))) {
                    exists = true;
                    eventLog.warn("告警ID已存在于事件中 - 事件ID: {}, 告警ID: {}", event.getId(), newAlarmId);
                    break;
                }
            }

            if (!exists) {
                alarmIdsArray.add(newAlarmId);
                event.setAlarmIds(alarmIdsArray.toJSONString());
            } else {
                // 如果已存在，需要调整告警计数
                event.setAlarmCount(event.getAlarmCount() - 1);
                eventLog.warn("跳过重复告警ID，调整告警计数 - 事件ID: {}, 告警ID: {}", event.getId(), newAlarmId);
            }

            // 3. 更新温度统计（如果是温度告警）
            if (newAlarm.getAlarmType() == 3 && newAlarm.getMeterAlarmTemperature() != null) {
                updateTemperatureStats(event, newAlarm.getMeterAlarmTemperature());
            }

            // 4. 更新激光器温度（如果是激光器故障）
            if (newAlarm.getAlarmType() == 2 && newAlarm.getLaserTemperature() != null) {
                event.setLaserTemperature(newAlarm.getLaserTemperature());
            }

            // 5. 执行更新
            pjAlarmEventMapper.updatePjAlarmEvent(event);

            eventLog.debug("更新事件统计信息 - 事件ID: {}, 告警计数: {}, 最后告警ID: {}, 新关闭时间: {}",
                    event.getId(), event.getAlarmCount(), event.getLastAlarmId(), event.getAlarmCloseTime());

        } catch (Exception e) {
            eventLog.error("更新事件统计信息失败 - 事件ID: {}, 错误: {}", event.getId(), e.getMessage(), e);
            throw new RuntimeException("更新事件统计信息失败", e);
        }
    }

    /**
     * 更新温度统计
     */
    private void updateTemperatureStats(PjAlarmEvent event, BigDecimal newTemperature) {
        if (event.getMaxTemperature() == null || newTemperature.compareTo(event.getMaxTemperature()) > 0) {
            event.setMaxTemperature(newTemperature);
        }
        if (event.getMinTemperature() == null || newTemperature.compareTo(event.getMinTemperature()) < 0) {
            event.setMinTemperature(newTemperature);
        }

        // 计算新的平均温度（简化计算，实际应该重新计算所有温度的平均值）
        if (event.getAvgTemperature() != null) {
            BigDecimal total = event.getAvgTemperature().multiply(BigDecimal.valueOf(event.getAlarmCount() - 1))
                    .add(newTemperature);
            BigDecimal newAvg = total.divide(BigDecimal.valueOf(event.getAlarmCount()), 2, RoundingMode.HALF_UP);
            event.setAvgTemperature(newAvg);
        } else {
            event.setAvgTemperature(newTemperature);
        }
    }

    /**
     * 生成事件编号 - E + yymmddHHmmss + 顺序号
     */
    private String generateEventNo(PjAlarmRecord alarmRecord, Integer eventKey) {
        try {
            // 格式化时间：yyMMddHHmmss
            SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
            String timeStr = sdf.format(new Date());

            // 生成3位顺序号（使用随机数，实际生产建议用序列）
            Random random = new Random();
            int sequence = random.nextInt(1000);

            String eventNo = "E" + timeStr + String.format("%03d", sequence);

            eventLog.debug("生成事件编号: {}", eventNo);
            return eventNo;

        } catch (Exception e) {
            eventLog.error("生成事件编号失败，使用备用方案", e);
            // 备用方案
            return "E" + System.currentTimeMillis() % 1000000000L;
        }
    }

    /**
     * 获取告警类型前缀
     */
    private String getAlarmTypePrefix(Integer alarmType) {
        switch (alarmType) {
            case 1: return "FIBER";    // 断纤告警
            case 2: return "LASER";    // 激光器故障
            case 3: return "TEMP";     // 温度告警
            default: return "UNKNOWN";
        }
    }

    /**
     * 获取告警类型名称
     */
    private String getAlarmTypeName(Integer alarmType) {
        switch (alarmType) {
            case 1: return "断纤告警";
            case 2: return "激光器故障";
            case 3: return "温度告警";
            default: return "未知类型";
        }
    }

    /**
     * 关闭超时事件
     */
    @Override
    @Transactional
    public void closeTimeoutEvents() {
        try {
            eventLog.info("开始检查超时事件");

            // 计算超时阈值（当前时间）
            Date thresholdTime = new Date();

            // 查询需要关闭的事件（alarm_close_time <= 当前时间）
            List<PjAlarmEvent> eventsToClose = pjAlarmEventMapper.selectEventsToClose(thresholdTime);

            if (eventsToClose.isEmpty()) {
                eventLog.info("没有需要关闭的超时事件");
                return;
            }

            eventLog.info("找到 {} 个需要关闭的超时事件", eventsToClose.size());

            List<Long> eventIds = eventsToClose.stream()
                    .map(PjAlarmEvent::getId)
                    .collect(Collectors.toList());

            // 批量更新事件状态为关闭（1）
            int updatedCount = pjAlarmEventMapper.updateEventStatusBatch(eventIds, 1);

            eventLog.info("成功关闭 {} 个超时事件", updatedCount);

            // 记录关闭的详细信息
            for (PjAlarmEvent event : eventsToClose) {
                eventLog.info("关闭事件 - 事件ID: {}, 事件编号: {}, 类型: {}, 告警计数: {}, 最后告警时间: {}, 关闭时间: {}",
                        event.getId(), event.getEventNo(), getAlarmTypeName(event.getAlarmType()),
                        event.getAlarmCount(), event.getAlarmCloseTime(), thresholdTime);
            }

        } catch (Exception e) {
            eventLog.error("关闭超时事件失败 - 错误: {}", e.getMessage(), e);
            throw new RuntimeException("关闭超时事件失败", e);
        }
    }

    /**
     * 查询活跃的事件
     */
    @Override
    public List<PjAlarmEvent> selectActiveEvents() {
        return pjAlarmEventMapper.selectActiveEvents();
    }

    /**
     * 处理事件（标记为已处理）
     */
    @Override
    @Transactional
    public int handleEvent(Long eventId, String handledResult, String handledBy, Date handledTime) {
        try {
            PjAlarmEvent event = pjAlarmEventMapper.selectPjAlarmEventById(eventId);
            if (event == null) {
                eventLog.warn("处理事件失败 - 事件不存在: {}", eventId);
                return 0;
            }

            // 使用Mapper的handleEvent方法
            int result = pjAlarmEventMapper.handleEvent(eventId, handledResult, handledBy, handledTime);

            if (result > 0) {
                eventLog.info("事件处理完成 - 事件ID: {}, 类型: {}, 处理人: {}, 处理结果: {}",
                        eventId, getAlarmTypeName(event.getAlarmType()), handledBy, handledResult);
            }

            return result;

        } catch (Exception e) {
            eventLog.error("处理事件失败 - 事件ID: {}, 错误: {}", eventId, e.getMessage(), e);
            throw new RuntimeException("处理事件失败", e);
        }
    }

    /**
     * 根据设备、通道、类型、米标查询活跃事件
     */
    @Override
    public List<PjAlarmEvent> selectActiveEventsByDeviceChannelTypeMeter(String deviceNo, Integer chanel, Integer alarmType, Integer meterMark) {
        return pjAlarmEventMapper.selectActiveEventsByDeviceChannelTypeMeter(deviceNo, chanel, alarmType, meterMark);
    }

    /**
     * 根据设备、通道、类型查询活跃事件（用于激光器故障）
     */
    @Override
    public List<PjAlarmEvent> selectActiveEventsByDeviceChannelType(String deviceNo, Integer chanel, Integer alarmType) {
        return pjAlarmEventMapper.selectActiveEventsByDeviceChannelType(deviceNo, chanel, alarmType);
    }
}